﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.IO.Ports;
using System.IO;

namespace lbc_02_reader
{
    public partial class MainWindow : Form
    {
        SerialPort m_connexion = new SerialPort();
        string m_chaine, m_date, m_checksum, m_noArticle, m_prixArticle, m_taxe, m_quantite, m_data;
        DateTime m_DateTime;
        public readonly double m_TauxTPS = 0.05; // Trouver TPS
        public readonly double m_TauxTVQ = 0.095; // Calculer la TVQ = montant de base + TPS
        public MainWindow()
        {
            InitializeComponent();
            m_chaine = m_date = m_checksum = m_noArticle = m_prixArticle = m_taxe = m_quantite = m_data = "";
        }

        // On va faire un contrôle de l'inventaire.
        // S'il y a un item, on le sort.
        private string CheckInventory(string data)
        {
            
            int index = -1;
            string quantité = "";
            List <string> maListe = new List<string>();
            FileStream fs = new FileStream("..\\..\\Inventaire.txt", FileMode.Open,
                    FileAccess.ReadWrite, FileShare.None);
            StreamReader sr = new StreamReader(fs);

            // Met les articles dans une liste
            while (sr.Peek() >= 0)
            {
                maListe.Add(sr.ReadLine());
            }
            sr.Close();
            sr.Dispose();
            fs.Close();
            fs.Dispose();

            // on vas ramasser l'index de l'article
            int compte = 0;
            foreach (string article in maListe)
            {
                
                if (article.Remove(article.IndexOf(',')) == data)
                {
                    index = compte;
                }
                compte++;
            }
            if (index > -1)
            {
                string remplacement = "";
                int nombre = 0;
                remplacement = maListe[index];
                nombre = Convert.ToInt32(remplacement.Remove(0, remplacement.IndexOf(',') + 1));
                if (nombre > 0)
                {
                    if (nombre == 1)
                        MessageBox.Show("Vous devez faire une commande pour le produit: " + data);
                    nombre--;
                    quantité = nombre.ToString();
                    remplacement = remplacement.Remove(remplacement.IndexOf(',')) + "," + quantité;
                    maListe.RemoveAt(index);
                    maListe.Add(remplacement);
                    FileStream fsw = new FileStream("..\\..\\Inventaire.txt", FileMode.Truncate, FileAccess.ReadWrite, FileShare.None);
                    StreamWriter sw = new StreamWriter(fsw);
                    foreach (string article in maListe)
                    {
                        sw.WriteLine(article);
                    }
                    sw.Close();
                    sw.Dispose();
                    fsw.Close();
                    fsw.Dispose();
                }
                else
                    quantité = "NULL";
            }
            return quantité;
        }

        // On calcule le total des articles
        private string CalculeTotal(double prix, string total)
        {
            string retour = "";
            double totalFin = Convert.ToDouble(total.Remove(total.IndexOf(' ')));
            prix += Convert.ToDouble(CalculeTaxe(prix));
            totalFin += prix;
            retour = ((int)((totalFin + 0.005) * 100) / 100.0).ToString();

            return retour;
        }

        // On va chercher le montant selon le numéro de l'article
        private double ChercheMontant(string noArticle)
        {
            double retour = 0.0;
            string aVerifier = "", montant = "";

            FileStream fs = new FileStream("..\\..\\Produit.txt", FileMode.Open,
                    FileAccess.Read, FileShare.None);
            StreamReader sr = new StreamReader(fs);
            while (sr.Peek() >= 0)
            {
                aVerifier = sr.ReadLine();
                montant = aVerifier.Remove(0, aVerifier.IndexOf(':') + 1);
                if (aVerifier.Remove(aVerifier.IndexOf(':')) == noArticle)
                    retour = Convert.ToDouble(montant);
            }

            sr.Close();
            sr.Dispose();
            fs.Close();
            fs.Dispose();

            return retour;
        }

        // Cette fonction prend un chiffre en entrée et calcule la taxe
        // elle retourne ensuite le montant sous la forme d'un string
        private string CalculeTaxe(double montant)
        {
            double retour = 0, TPS = 0, TVQ = 0;

            // Calcule TPS
            TPS = montant * m_TauxTPS;
            TPS = (int)((TPS + 0.005) * 100) / 100.0;

            // Calcule TVQ
            TVQ = (montant + TPS) * m_TauxTVQ;
            TVQ = (int)((TVQ + 0.005) * 100) / 100.0;

            retour = (int)((TPS + TVQ + 0.005) * 100) / 100.0;

            return retour.ToString(); 
        }

        // Coupe la tramme en morceau pour aller en chercher les informations pertinentes
        private void coupeChaine(string trame, string chk)
        {
            int year, month, day, hour, minute, second;
            // on va aller chercher la date et la placer dans une structure DateTime
            // en cas d'éventuelle manipulation un peu plus complexe. Sinon, c'est un bon exercice.
            string temporaire = trame.Remove(0,3);
            string temporaire2 = "";
            m_date = temporaire.Remove(6);
            temporaire2 = temporaire.Remove(2);
            month = Convert.ToInt32(temporaire2);
            temporaire2 = temporaire.Remove(0, 2);
            temporaire2 = temporaire2.Remove(2);
            day = Convert.ToInt32(temporaire2);
            temporaire2 = temporaire.Remove(0, 4);
            temporaire2 = temporaire2.Remove(2);
            year = Convert.ToInt32(temporaire2) + 2000;
            temporaire2 = temporaire.Remove(0, 6);
            temporaire2 = temporaire2.Remove(2);
            hour = Convert.ToInt32(temporaire2);
            temporaire2 = temporaire.Remove(0, 8);
            temporaire2 = temporaire2.Remove(2);
            minute = Convert.ToInt32(temporaire2);
            temporaire2 = temporaire.Remove(0, 10);
            temporaire2 = temporaire2.Remove(2);
            second = Convert.ToInt32(temporaire2);
            m_DateTime = new DateTime(year, month, day, hour, minute, second);
            // le checksum
            m_checksum = chk;
            // et le data
            temporaire = trame.Remove(0, trame.IndexOf(',') + 1);
            m_data = temporaire.Remove(temporaire.IndexOf(' '));
        }

        // Écrit la tramme dans le fichier Reception.txt
        private void WriteReception(string toWrite)
        {
            try
            {
                FileStream fs = new FileStream("..\\..\\Reception.txt", FileMode.Truncate,
                    FileAccess.ReadWrite, FileShare.None);
                byte[] chaine = System.Text.Encoding.GetEncoding(437).GetBytes(toWrite);
                int longueur = chaine.Length;
                // on écrit le data byte par byte dans le fichier Reception.txt
                for (int i = 0; i < longueur; i++)
                    fs.WriteByte(chaine[i]);
                fs.Close();
                fs.Dispose();
            }
            catch (Exception e)
            {
                MessageBox.Show(e.ToString());
            }
        }

        // Permet de se connecter sur un port choisi
        private void btn_Connect_Click(object sender, EventArgs e)
        {
            bool error = false;
            int index = lst_Port.SelectedIndex;
            string port = "", speed = "";
            if (index >= 0)
                port = lst_Port.Items[index].ToString();
            else
                error = true;
            index = lst_Speed.SelectedIndex;
            if (index >= 0)
                speed = lst_Speed.Items[index].ToString();
            else
                error = true;

            if (error == false)
            {
                try
                {
                    m_connexion.PortName = port;
                    m_connexion.BaudRate = Convert.ToInt32(speed);
                    m_connexion.Parity = System.IO.Ports.Parity.None;
                    m_connexion.ReadTimeout = 5000; // lire 5 secondes
                    m_connexion.Open();
                    grp_Read.Enabled = true;
                    btn_Connect.Enabled = false;
                    btn_Deconnect.Enabled = true;
                    txt_State.Text = "CONNECTÉ!";
                }
                catch (System.IO.IOException exc)
                {
                    MessageBox.Show(exc.ToString());
                    txt_State.Text = "ERREUR!";
                }
            }
            else
                MessageBox.Show("Assurez-vous d'avoir bien selectionné une vitesse et un port");
        }

        // Permet de liberer le port, donc de se reconnecter
        // avec d'autre configuration
        private void btn_Deconnect_Click(object sender, EventArgs e)
        {
            try
            {
                m_connexion.Close();
                grp_Read.Enabled = false;
                btn_Deconnect.Enabled = false;
                btn_Connect.Enabled = true;
                txt_State.Text = "Déconnecté";
            }
            catch (System.IO.IOException exc)
            {
                MessageBox.Show(exc.ToString());
                txt_State.Text = "ERREUR!";
            }
        }

        // Convertit un entier en Hexa et le retourne sous forme de string
        private string ConvertToHexa(int Entier, int op)
        {
            string[] HexaBin = {"0", "1", "2", "3", "4", "5", "6", "7", "8", 
                                     "9", "A", "B", "C", "D", "E", "F"};
            string StringConverted;
            StringConverted = "";
            int index, StringLength, HexaDec;
            index = StringLength = HexaDec = 0;
            string value = Entier.ToString();

            HexaDec = Entier;

            while (HexaDec != 0)
            {
                StringConverted = HexaBin[HexaDec % 16] + StringConverted;
                HexaDec = HexaDec / 16;
            }
            
            return StringConverted;
        }

        // Calcule le checksum du data et le retourne sous forme de string
        private string CalculeCheckSum(string data)
        {
            string retour = "";
            int somme = 0;

            for (int i = 0; i < data.Length; i++)
            {
                somme += Convert.ToInt32(data[i]);
            }

            // On passe l'entier somme et le transforme en Hexa et reviens sous la forme d'un string
            retour = ConvertToHexa(somme, 2);

            // On garde que les deux derniers chiffres
            retour = retour.Remove(0, retour.Length - 2);

            return retour;
        }

        // Va lire dans le buffer sur le port sélectionner
        // et commence à valider les données qui entre selon le protocole
        private void btn_Read_Click(object sender, EventArgs e)
        {
            int valeur = 0, longueur = 0;
            double prix = 0.0;
            string chksum = "", newChecksum = "", tramme = "";
            m_chaine = "";
            string checkInventaire = "";
            while (m_connexion.BytesToRead > 0)
            {
                valeur = m_connexion.ReadChar();
                m_chaine += (char)valeur;
            }
            
            // Ecriture dans le fichier Reception.txt
            WriteReception(m_chaine);

            // On va vérifier le checksum
            // On enlève les 3 derniers char et on garde les deux premiers comme checksum
            longueur = m_chaine.Length - 3;
            if (longueur > 3)
            {
                tramme = m_chaine.Remove(longueur);
                chksum = m_chaine[longueur].ToString() + m_chaine[longueur + 1].ToString();
                newChecksum = CalculeCheckSum(tramme);

                if (chksum == newChecksum)
                {
                    // On commence par envoyé un ack
                    string snak = ((char)6).ToString();
                    byte[] nak = new byte[snak.Length];
                    nak = System.Text.Encoding.GetEncoding(437).GetBytes(snak);
                    m_connexion.Write(nak, 0, nak.Length);

                    // On va couper la chaine recu
                    coupeChaine(m_chaine, chksum);
                    //On vérifie si certaines conditions sont bonne relativement à l'Heure
                    // et à la date
                    string[] dateAchecker = new string[4];
                    dateAchecker[0] = string.Format("{0:dd-MM-yy}", m_DateTime);
                    dateAchecker[1] = string.Format("25-12-02", m_DateTime);
                    dateAchecker[2] = string.Format("14-10-02", m_DateTime);
                    dateAchecker[3] = string.Format("01-01-03", m_DateTime);
                    if (m_DateTime.Hour < 8 || m_DateTime.Hour > 17 || (dateAchecker[0] == dateAchecker[1])
                        || (dateAchecker[0] == dateAchecker[2]) || (dateAchecker[0] == dateAchecker[3]))
                        return;

                    // affiche l'information dans les boîtes d'édition
                    txt_itemName.Text = m_data;
                    txt_Date.Text = string.Format("{0:dd-MM-yyyy} @ {1:hh:mm:ss}", m_DateTime, m_DateTime);
                    txt_Chksum.Text = m_checksum;
                    checkInventaire = CheckInventory(m_data);
                    
                    // On s'occupe des chiffres et inventaires
                    prix = ChercheMontant(m_data);
                    if (prix > 0)
                    {
                        string prixtemp = string.Format("{0:C} $", CalculeTaxe(prix));
                        txt_Taxe.Text = prixtemp;
                        prixtemp = string.Format("{0:c} $",prix.ToString());
                        txt_Prix.Text = prixtemp;
                        if (checkInventaire != "NULL")
                        {
                            txt_Total.Text = CalculeTotal(prix, txt_Total.Text) + " $";
                            txt_nbInventaire.Text = checkInventaire;
                        }
                        else
                            txt_nbInventaire.Text = "0";     
                    }
                }
                else
                {
                    MessageBox.Show("Pas pareil");
                    txt_Chksum.Text = "";
                    txt_Date.Text = "";
                    txt_itemName.Text = "Invalide";
                    txt_nbInventaire.Text = "";
                    txt_Prix.Text = "";
                    txt_Taxe.Text = "";
                    txt_Total.Text = "";
                    // Le message n'a pas fonctionner, alors on doit l'archiver
                    FileStream fs = new FileStream("..\\..\\ArchiveErreur.txt", FileMode.Append,
                    FileAccess.Write, FileShare.None);
                    StreamWriter sw = new StreamWriter(fs);
                    sw.WriteLine(tramme);
                    sw.Close();
                    sw.Dispose();
                    fs.Close();
                    fs.Dispose();
                    // maintenant on envoie un nack
                    string snak = ((char)21).ToString();
                    byte[] nak = new byte[snak.Length];
                    nak = System.Text.Encoding.GetEncoding(437).GetBytes(snak);
                    m_connexion.Write(nak, 0, nak.Length);
                }
            }
        }
    }
}
